package application

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"shimmer/neusoft_club_backend/controllers/cons"
	"shimmer/neusoft_club_backend/controllers/utils"
	"shimmer/neusoft_club_backend/dao/domain"
	"shimmer/neusoft_club_backend/services"
	"shimmer/neusoft_club_backend/services/club_service"
	"shimmer/neusoft_club_backend/services/errs"
)

type updateUserApplicationMutation struct {
	Content map[string]interface{} `json:"content" form:"content" binding:"required"`
}

// @Summary 使用ID查找用户申请
// @Description
// @Tags 社团,用户,表单
// @Param ApplicationID path integer true "AID"
// @Success 200 {object} domain.UserApplicationDTO
// @Router /api/user/self/application/single/{ApplicationID} [get]
func findUsersApplicationByID(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	applicationBinding := &cons.ApplicationUriParamBinding{}
	if err = c.ShouldBindUri(applicationBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	application, err := club_service.FindUsersApplicationAndAuth(applicationBinding.ApplicationID, user.ID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.JSON(http.StatusOK, application)
}

// @Summary 更新用户申请信息
// @Description
// @Tags 社团,用户,表单
// @Param ApplicationID path integer true "AID"
// @Param content body updateUserApplicationMutation true "新的信息"
// @Success 200 {object} domain.UserApplicationDTO
// @Router /api/user/self/application/single/{ApplicationID} [post]
func updateUsersApplication(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	mutation := &updateUserApplicationMutation{}
	if err = c.ShouldBind(mutation); err != nil {
		services.AbortWithError(c, err)
		return
	}
	applicationBinding := &cons.ApplicationUriParamBinding{}
	if err = c.ShouldBindUri(applicationBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	application, err := club_service.FindUsersApplicationAndAuth(applicationBinding.ApplicationID, user.ID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if application.Status == nil {
		services.AbortWithError(c, errs.ErrFormStatusIsBroken)
		return
	}
	if application.Status.Type != domain.ClubFormStatusFlowTypeDraft {
		services.AbortWithError(c, errs.ErrFormAlreadyPublished)
		return
	}
	if err = club_service.UpdateApplication(application.ID, mutation.Content); err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.AbortWithStatus(http.StatusNoContent)
}

// @Summary 获取自己的所有申请
// @Description
// @Tags 用户
// @accept json
// @Produce json
// @Param page query integer true "页数"
// @Param size query integer true "页面大小"
// @Success 200 {object} []domain.UserApplicationDTO
// @Router /api/user/self/application [get]
func findAllUsersApplication(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	pageQuery, err := utils.GetPaginationFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	applications, err := club_service.FindAllUsersApplication(user.ID, pageQuery)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.JSON(http.StatusOK, applications)
}

// @Summary 公开自己的申请
// @Description
// @Tags 用户
// @Param ApplicationID path integer true "AID"
// @Success 200 {object} domain.ClubFormStatusFlowDTO
// @Router /api/user/self/application/single/{ApplicationID}/publish [post]
func publishUserApplication(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}

	applicationBinding := &cons.ApplicationUriParamBinding{}

	if err = c.ShouldBindUri(applicationBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}

	application, err := club_service.FindUsersApplicationByID(applicationBinding.ApplicationID)

	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if application.UserID != user.ID {
		isAdmin, _ := club_service.CheckIsAdmin(user.ID)
		if !isAdmin {
			services.AbortWithError(c, errs.ErrNotAdmin)
			return
		}
	}
	if application.Status == nil {
		services.AbortWithError(c, errs.ErrFormStatusIsBroken)
		return
	}
	if application.Status.Type != domain.ClubFormStatusFlowTypeDraft {
		services.AbortWithError(c, errs.ErrFormAlreadyPublished)
		return
	}
	status, err := club_service.PublishApplication(application)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.JSON(http.StatusOK, status)
}

// @Summary 撤销自己的申请
// @Description
// @Tags 用户
// @Param ApplicationID path integer true "AID"
// @Success 204
// @Router /api/user/self/application/single/{ApplicationID} [delete]
func cancelApplication(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}

	applicationBinding := &cons.ApplicationUriParamBinding{}

	if err = c.ShouldBindUri(applicationBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	application, err := club_service.FindUsersApplicationByID(applicationBinding.ApplicationID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if application.Status.Type != domain.ClubFormStatusFlowTypeDraft {
		services.AbortWithError(c, errs.ErrFormAlreadyPublished)
		return
	}
	if application.UserID != user.ID {
		isAdmin, _ := club_service.CheckIsAdmin(user.ID)
		if !isAdmin {
			services.AbortWithError(c, errs.ErrNotAdmin)
			return
		}
	}

	if err = club_service.CancelApplication(application); err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.AbortWithStatus(http.StatusNoContent)
}

func ConfigureUserApplicationController(r *gin.RouterGroup) {
	r.GET(fmt.Sprintf("/single/:%s", cons.ApplicationUriParam), findUsersApplicationByID)
	r.POST(fmt.Sprintf("/single/:%s", cons.ApplicationUriParam), updateUsersApplication)
	r.POST(fmt.Sprintf("/single/:%s/publish", cons.ApplicationUriParam), publishUserApplication)
	r.DELETE(fmt.Sprintf("/single/:%s", cons.ApplicationUriParam), cancelApplication)
	r.GET("/", findAllUsersApplication)
}
